package com.atguigu.guli.service.trade.service.impl;

import com.atguigu.guli.common.util.HttpClientUtils;
import com.atguigu.guli.common.util.StreamUtils;
import com.atguigu.guli.service.base.dto.CourseDto;
import com.atguigu.guli.service.base.dto.MemberDto;
import com.atguigu.guli.service.base.exception.GuliException;
import com.atguigu.guli.service.base.result.R;
import com.atguigu.guli.service.base.result.ResultCodeEnum;
import com.atguigu.guli.service.trade.entity.Order;
import com.atguigu.guli.service.trade.entity.PayLog;
import com.atguigu.guli.service.trade.feign.EduCourseService;
import com.atguigu.guli.service.trade.feign.UcenterMemberService;
import com.atguigu.guli.service.trade.mapper.OrderMapper;
import com.atguigu.guli.service.trade.service.OrderService;
import com.atguigu.guli.service.trade.service.PayLogService;
import com.atguigu.guli.service.trade.util.OrderNoUtils;
import com.atguigu.guli.service.trade.util.WeixinPayProperties;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.wxpay.sdk.WXPayUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * <p>
 * 订单 服务实现类
 * </p>
 *
 * @author atguigu
 * @since 2021-08-12
 */
@Service
@Transactional //多个sql更新操作 必须同时成功才会被提交
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {

    @Autowired
    private UcenterMemberService ucenterMemberService;
    @Autowired
    private EduCourseService eduCourseService;

    @Override
    public String saveOrder(String courseId, String memberId) {

        //1.查询当前用户是否已有当前课程的订单
        QueryWrapper<Order> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("course_id",courseId);
        queryWrapper.eq("member_id",memberId);
        Order orderExist = baseMapper.selectOne(queryWrapper);
        if (orderExist != null){
            return orderExist.getId(); // 如果订单已存在，则直接返回订单id
        }


        //2.查询课程信息
        R rCourse = eduCourseService.getCourseDtoById(courseId);
        /* 这样写不知道可以不，==> 返回LinkedHashMap无法进行强制类型转换
        CourseDto courseDto = (CourseDto) rCourse.getData().get("courseDto");*/

        ObjectMapper mapper = new ObjectMapper();
        CourseDto courseDto = mapper.convertValue(rCourse.getData().get("courseDto"), CourseDto.class);
        if (courseDto == null){
            throw new GuliException(ResultCodeEnum.ILLEGAL_CALLBACK_REQUEST_ERROR);
        }

        //3.查询用户信息
        R rMember = ucenterMemberService.getMemberDtoById(memberId);
        MemberDto memberDto = mapper.convertValue(rMember.getData().get("memberDto"), MemberDto.class);
        if (memberDto == null){
            try {
                throw new Exception("回调错误");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        //4.创建订单
        Order order = new Order();
        order.setOrderNo(OrderNoUtils.getOrderNo());
        order.setCourseId(courseId);
        order.setCourseCover(courseDto.getCover());
        order.setCourseTitle(courseDto.getTitle());
        order.setTeacherName(courseDto.getTeacherName());
        //什么玩意
        Long totalFee = courseDto.getPrice().multiply(new BigDecimal(100)).longValue();
        order.setTotalFee(totalFee);

        order.setMemberId(memberId);
        order.setMobile(memberDto.getMobile());
        order.setNickname(memberDto.getNickname());
        order.setStatus(0); // 未支付
        order.setPayType(1); // 微信支付
        baseMapper.insert(order);
        return order.getId();

    }

    @Override
    public Order getByOrderId(String orderId, String memberId) {
        QueryWrapper<Order> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id",orderId);
        queryWrapper.eq("member_id",memberId);
        Order order = baseMapper.selectOne(queryWrapper);
        return order;
    }

    /*@Override
    public Order getOrderByOrderNo(String orderNo) {
        QueryWrapper<Order> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("order_no", orderNo);
        return baseMapper.selectOne(queryWrapper);
    }*/

    @Override
    public Boolean isBuyByCourseId(String memberId, String courseId) {
        QueryWrapper<Order> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("member_id",memberId);
        queryWrapper.eq("course_id",courseId);
        queryWrapper.eq("status",1);
        Integer count = baseMapper.selectCount(queryWrapper);
        return count.intValue() > 0;
    }

    @Autowired
    WeixinPayProperties weixinPayProperties;
    @Autowired
    PayLogService payLogService;

    @Override
    public R createNative(String orderId, HttpServletRequest request) {
        try{
            Order order = this.getById(orderId);
            //访问wx的统一下单接口并配置参数
            String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
            //wx提供一个sdk包 提供了将xml转为map
            //为网络请求准备参数
            HashMap<String, String> map = new HashMap<>();
            map.put("appid",weixinPayProperties.getAppId());
            map.put("mch_id",weixinPayProperties.getPartner());
            map.put("nonce_str", WXPayUtil.generateNonceStr());//随机字符串
            map.put("body",order.getCourseTitle());//展示给wx用户的商品信息
            map.put("out_trade_no",order.getOrderNo());//订单编号
            map.put("total_fee",order.getTotalFee()+"");
            map.put("spbill_create_ip",request.getRemoteHost());//客户端IP地址
            map.put("notify_url", weixinPayProperties.getNotifyUrl());//用户扫描本次生成的二维码支付成功后的回调
            map.put("trade_type","NATIVE");//本次是web项目的支付

            //指定秘钥 根据map生成签名
            String signedXmlStr = WXPayUtil.generateSignedXml(map,weixinPayProperties.getPartnerKey());

            //发起网络请求并将xml作为参数传入
            HttpClientUtils client = new HttpClientUtils(url);
            System.out.println("signedXmlStr" + signedXmlStr);
            client.setXmlParam(signedXmlStr);
            client.post();

            String content = client.getContent();

            boolean signatureValid = WXPayUtil.isSignatureValid(content, weixinPayProperties.getPartnerKey());
            if (!signatureValid){
                //签名或数据被篡改
                throw new GuliException(ResultCodeEnum.PAY_UNIFIEDORDER_ERROR);
            }
            Map<String, String> resultMap = WXPayUtil.xmlToMap(content);
            System.out.println("resultMap = "+resultMap);
            if (!"SUCCESS".equals(resultMap.get("return_code")) ||
                !"SUCCESS".equals(resultMap.get("result_code"))){
                //wx响应失败
                throw new GuliException(ResultCodeEnum.PAY_UNIFIEDORDER_ERROR);
            }
            String codeUrl = resultMap.get("code_url");
            //返回二维码连接 前端页面获取后可以转换为二维码图片显示到页面中
            return R.ok().data("code_url",codeUrl)
                    .data("out_trade_no",order.getOrderNo())
                    .data("total_fee",order.getTotalFee())
                    .data("courseId",order.getCourseId())
                    .data("orderId",order.getId());
        }catch (Exception e){
            throw new GuliException(ResultCodeEnum.PAY_UNIFIEDORDER_ERROR,e);
        }
    }

    @Override
    public String notifyUrl(HttpServletRequest request) {
        Map returnMap = new HashMap();//用来存放给微信的响应数据
        returnMap.put("return_code","FALL");
        returnMap.put("return_msg","FALL");
        try{
            //wx传入的用户支付的结果
            String callbackStr = StreamUtils.inputStream2String(request.getInputStream(), "UTF-8");
            //验证签名是否正确
            boolean signatureValid = WXPayUtil.isSignatureValid(callbackStr, weixinPayProperties.getPartnerKey());
            if (!signatureValid){
                returnMap.put("return_msg","签名失败");
                return WXPayUtil.mapToXml(returnMap);
            }
            //验证用户实付金额和订单是否一致
            Map<String, String> map = WXPayUtil.xmlToMap(callbackStr);
            System.out.println(map);
            if (!"SUCCESS".equals(map.get("return_code"))){
                returnMap.put("return_msg","响应失败");
                return WXPayUtil.mapToXml(returnMap);
            }
            String cash_fee = map.get("cash_fee");//用户支付金额
            String out_trade_no = map.get("out_trade_no");
            //查询数据库中订单的金额
            LambdaQueryWrapper<Order> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(Order::getOrderNo,out_trade_no);
            Order order = this.getOne(queryWrapper);
            if (order==null || order.getTotalFee() != Long.parseLong(cash_fee)){
                returnMap.put("return_msg","用户支付金额和订单金额不一致");
                return WXPayUtil.mapToXml(returnMap);
            }
            //订单支付成功
            //更新订单状态
            if (order.getStatus() == 0){
                LambdaUpdateWrapper<Order> updateWrapper = new LambdaUpdateWrapper<>();
                updateWrapper.set(Order::getStatus,1 );//支付状态 1已支付
                updateWrapper.set(Order::getPayType,1);//支付类型
                this.update(updateWrapper);
                //保存订单支付日志
                PayLog payLog = new PayLog();
                payLog.setPayType(1);
                payLog.setPayTime(new Date());
                payLog.setTotalFee(order.getTotalFee());
                payLog.setOrderNo(order.getOrderNo());
                payLog.setTradeState("1");
                payLog.setTransactionId(map.get("transaction_id"));
                payLog.setAttr(callbackStr);
                payLogService.save(payLog);
                //更新课程销量，远程访问service-edu更新课程表课程的销量
                eduCourseService.updateSales(order.getCourseId());

            }
            returnMap.put("return_code","SUCCESS");
            returnMap.put("return_msg","OK");
            return WXPayUtil.mapToXml(returnMap);
        }catch (Exception e){
            returnMap.put("return_msg","出现异常");
            try {
                return WXPayUtil.mapToXml(returnMap);
            } catch (Exception e1) {
                throw new GuliException(ResultCodeEnum.ILLEGAL_CALLBACK_REQUEST_ERROR,e);
            }
        }

    }


}
